import 'dart:async';

import 'package:geolocator/geolocator.dart';
import 'package:get/get.dart';
import 'package:location_test/app/data/datasources/remote/mqtt_service.dart';
import 'package:location_test/app/domain/models/ble_beacon.dart';
import 'package:location_test/app/domain/repositories/device_repository.dart';
import 'package:location_test/app/domain/repositories/settings_repository.dart';
import 'package:nmea_plugin/nmea_models.dart';

class HomeController extends GetxController {
  // --- 依赖注入 ---
  final MqttService _mqttService = Get.find();
  final ISettingsRepository _settingsRepo = Get.find();
  final IDeviceRepository _deviceRepo = Get.find();

  // --- 响应式状态 ---
  // MQTT
  Rx<MqttConnectionState> get mqttConnectionState => _mqttService.connectionState;
  final mqttBrokerAddress = ''.obs;
  final lastMessage = '请配置 MQTT 后再启用数据发送'.obs;

  // 设备状态
  final batteryLevel = (-1).obs;
  final currentPosition = Rx<Position?>(null);

  // NMEA 信息
  final satellitesInUse = Rx<int?>(null);
  final hdop = Rx<double?>(null);
  final vdop = Rx<double?>(null);
  final nmeaHistory = <NmeaMessage>[].obs;

  // 数据上报
  final isSendingData = false.obs;
  final sendInterval = 5.0.obs;
  final positionHistory = <Position>[].obs;
  final uploadHistory = <Map<String, dynamic>>[].obs;

  // BLE 扫描
  final isBleReceiving = false.obs;
  final bleReadings = <BleBeacon>[].obs;

  // --- 内部状态 ---
  StreamSubscription? _locationSub;
  StreamSubscription? _batterySub;
  StreamSubscription? _nmeaSub;
  StreamSubscription? _bleSub;
  Timer? _publishTimer;
  final Map<String, BleBeacon> _bleBuffer = {};
  static const Duration _bleRetention = Duration(seconds: 30);

  @override
  void onInit() {
    super.onInit();
    _loadSettings();
    _initListeners();
  }

  void _loadSettings() {
    mqttBrokerAddress.value = _settingsRepo.getMqttBroker();
    sendInterval.value = _settingsRepo.getSendInterval().toDouble();
    if (mqttBrokerAddress.isNotEmpty) {
      _mqttService.setup(mqttBrokerAddress.value);
    }
  }

  void _initListeners() {
    _batterySub = _deviceRepo.getBatteryLevelStream().listen((level) {
      batteryLevel.value = level;
    });

    _nmeaSub = _deviceRepo.getNmeaMessageStream().listen((message) {
      nmeaHistory.insert(0, message);
      if (nmeaHistory.length > 200) nmeaHistory.removeLast();

      if (message is GsaMessage) {
        if (message.mode2 != 1) {
          hdop.value = message.hdop;
          vdop.value = message.vdop;
        } else {
          hdop.value = null;
          vdop.value = null;
        }
      } else if (message is GgaMessage) {
        satellitesInUse.value =
            message.fixQuality != null && message.fixQuality! > 0
                ? message.numberOfSatellites
                : 0;
      }
    });

    _mqttService.connectionState.listen((state) {
      if (!isSendingData.value) return;

      if (state == MqttConnectionState.connected) {
        _startPublishing();
        lastMessage.value = 'MQTT 已连接，继续发送数据';
      } else {
        _stopPublishing();
        if (state != MqttConnectionState.connecting) {
          lastMessage.value = 'MQTT 连接异常，已暂停发送';
        }
      }
    });
  }

  // --- MQTT & 配置 ---
  Future<void> updateMqttBroker(String newAddress) async {
    mqttBrokerAddress.value = newAddress;
    await _settingsRepo.saveMqttBroker(newAddress);
    _mqttService.disconnect();
    _mqttService.setup(newAddress);
  }

  void connectMqtt() {
    if (mqttBrokerAddress.isEmpty) {
      lastMessage.value = '请先填写 MQTT 服务器地址';
      return;
    }
    if (_mqttService.connectionState.value == MqttConnectionState.connected ||
        _mqttService.connectionState.value == MqttConnectionState.connecting) {
      return;
    }
    _mqttService.connect();
  }

  void disconnectMqtt() => _mqttService.disconnect();

  void setSendInterval(double newInterval) {
    sendInterval.value = newInterval;
    _settingsRepo.saveSendInterval(newInterval.toInt());
    if (isSendingData.value &&
        _mqttService.connectionState.value == MqttConnectionState.connected) {
      _startPublishing();
    }
  }

  // --- 定位与 BLE 控制 ---
  void toggleSendingData(bool value) {
    isSendingData.value = value;
    if (value) {
      _startLocationUpdates();
      if (_mqttService.connectionState.value == MqttConnectionState.connected) {
        _startPublishing();
      } else {
        lastMessage.value = 'MQTT 未连接，正在尝试重连';
        connectMqtt();
      }
    } else {
      _stopPublishing();
      _stopLocationUpdates();
      positionHistory.clear();
      _bleBuffer.clear();
      lastMessage.value = '已停止数据发送';
    }
  }

  Future<void> toggleBleReceiving(bool value) async {
    if (value == isBleReceiving.value) return;

    if (value) {
      try {
        await _deviceRepo.startBleScan();
        _bleSub?.cancel();
        _bleSub = _deviceRepo.getBleBeaconStream().listen(
          (beacons) {
            if (!isBleReceiving.value) return;
            if (beacons.isEmpty) {
              bleReadings.clear();
              return;
            }

            final List<BleBeacon> latest = _deduplicateBeacons(beacons);
            bleReadings.assignAll(latest);
            _mergeBleBuffer(latest);
          },
          onError: (error) {
            final String message = error.toString().replaceFirst('Exception: ', '');
            lastMessage.value = '蓝牙扫描异常: $message';
          },
        );
        isBleReceiving.value = true;
        lastMessage.value = '已开启蓝牙广播扫描';
      } catch (e) {
        isBleReceiving.value = false;
        await _bleSub?.cancel();
        _bleSub = null;
        final String message = e.toString().replaceFirst('Exception: ', '');
        lastMessage.value = '蓝牙扫描启动失败: $message';
      }
    } else {
      await _deviceRepo.stopBleScan();
      await _bleSub?.cancel();
      _bleSub = null;
      isBleReceiving.value = false;
      bleReadings.clear();
      _bleBuffer.clear();
      lastMessage.value = '已关闭蓝牙广播扫描';
    }
  }

  void _startLocationUpdates() {
    _locationSub?.cancel();
    _locationSub = _deviceRepo.getPositionStream().listen(
      (pos) {
        currentPosition.value = pos;
        positionHistory.add(pos);
      },
      onError: (e) {
        lastMessage.value = '定位失败: $e';
      },
    );
  }

  void _stopLocationUpdates() {
    _locationSub?.cancel();
    _locationSub = null;
  }

  void _startPublishing() {
    _publishTimer?.cancel();
    _publishTimer = Timer.periodic(
      Duration(seconds: sendInterval.value.toInt()),
      (_) => _publishMessage(),
    );
  }

  void _stopPublishing() {
    _publishTimer?.cancel();
    _publishTimer = null;
  }

  void _publishMessage() {
    if (_mqttService.connectionState.value != MqttConnectionState.connected ||
        positionHistory.isEmpty) {
      return;
    }

    final List<Map<String, dynamic>> gnssPoints = positionHistory.map((pos) {
      return {
        'at': pos.latitude.toStringAsFixed(8),
        'on': pos.longitude.toStringAsFixed(8),
        'la': pos.altitude.toStringAsFixed(2),
        'sa': satellitesInUse.value ?? 0,
      };
    }).toList();

    final List<Map<String, dynamic>> blePayload = _sortedBleList()
        .map((e) => e.toJson())
        .toList();

    final Map<String, dynamic> data = {
      'gn': gnssPoints,
      'lb': blePayload,
      'im': _mqttService.clientId,
      'el': batteryLevel.value,
      't': (DateTime.now().millisecondsSinceEpoch / 1000).round(),
      'f': sendInterval.value.toInt(),
      'HDOP': hdop.value,
      'VDOP': vdop.value,
    };

    _mqttService.publish(data);
    lastMessage.value = '已上报 ${DateTime.now().toIso8601String()}';

    uploadHistory.insert(0, data);
    if (uploadHistory.length > 100) {
      uploadHistory.removeLast();
    }

    positionHistory.clear();
    _bleBuffer.clear();
  }

  List<BleBeacon> _deduplicateBeacons(List<BleBeacon> source) {
    final Map<String, BleBeacon> latest = {};
    for (final BleBeacon beacon in source) {
      final BleBeacon? existing = latest[beacon.key];
      if (existing == null || beacon.timestamp.isAfter(existing.timestamp)) {
        latest[beacon.key] = beacon;
      }
    }
    final List<BleBeacon> ordered = latest.values.toList()
      ..sort((a, b) => b.timestamp.compareTo(a.timestamp));
    return ordered;
  }

  void _mergeBleBuffer(List<BleBeacon> incoming) {
    final DateTime now = DateTime.now();
    final DateTime cutoff = now.subtract(_bleRetention);
    _bleBuffer.removeWhere((_, beacon) => beacon.timestamp.isBefore(cutoff));

    for (final BleBeacon beacon in incoming) {
      _bleBuffer[beacon.key] = beacon;
    }

    final List<BleBeacon> ordered = _sortedBleList();

    _bleBuffer.clear();
    for (final BleBeacon beacon in ordered) {
      _bleBuffer[beacon.key] = beacon;
    }
  }

  List<BleBeacon> _sortedBleList() {
    final List<BleBeacon> ordered = _bleBuffer.values.toList()
      ..sort((a, b) => b.timestamp.compareTo(a.timestamp));
    return ordered;
  }

  @override
  void onClose() {
    _locationSub?.cancel();
    _batterySub?.cancel();
    _nmeaSub?.cancel();
    _bleSub?.cancel();
    _publishTimer?.cancel();
    _deviceRepo.stopBleScan();
    _mqttService.disconnect();
    super.onClose();
  }
}
